﻿// --------------------------------------------------------------------------------------------------------------------- 
// <copyright file="Transition.cs" company="Scrum for Team System">
//   None
// </copyright>
// <summary>
//   Defines the Transition type.
// </summary>
// ---------------------------------------------------------------------------------------------------------------------
namespace ScrumForTeamSystem.EventService.TransitionService.DataStructures
{
    using System;
    using System.Globalization;
    using System.Xml.Serialization;

    /// <summary>
    /// Defines the Transition
    /// </summary>
    public class Transition
    {
        /// <summary>
        /// The wild card value
        /// </summary>
        public const string Wildcard = "*";

        /// <summary>
        /// Initializes a new instance of the <see cref="Transition"/> class.
        /// </summary>
        public Transition()
        {
            // Empty constructor for XMLSerialization only
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Transition"/> class.
        /// </summary>
        /// <param name="field">The field name.</param>
        /// <param name="from">The from value.</param>
        /// <param name="to">The to value.</param>
        public Transition(string field, string from, string to)
        {
            this.Field = field;
            this.From = from;
            this.To = to;
        }

        /// <summary>
        /// Gets or sets Field.
        /// </summary>
        /// <value>
        /// The field.
        /// </value>
        [XmlAttribute(AttributeName = "field")]
        public string Field
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets From value.
        /// </summary>
        /// <value>
        /// The from value.
        /// </value>
        [XmlAttribute(AttributeName = "from")]
        public string From
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets To value.
        /// </summary>
        /// <value>
        /// The to value.
        /// </value>
        [XmlAttribute(AttributeName = "to")]
        public string To
        {
            get;
            set;
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="target">The target.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator ==(Transition source, Transition target)
        {
            return CheckEquality(source, target);
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="target">The target.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator !=(Transition source, Transition target)
        {
            return !CheckEquality(source, target);
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <param name="obj">The comparison object.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
        /// </returns>
        /// <exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is null.</exception>
        public override bool Equals(object obj)
        {
            var transition = obj as Transition;
            return transition != null && this == transition;
        }

        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        public override int GetHashCode()
        {
            return this.ToString().GetHashCode();
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            return String.Format(CultureInfo.InvariantCulture, "{0}: {1} -> {2}", this.Field, this.From, this.To);
        }

        /// <summary>
        /// Checks the equality.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="target">The target.</param>
        /// <returns>
        /// <c>True</c> if the objects are equal; otherwise <c>false</c>.
        /// </returns>
        private static bool CheckEquality(Transition source, Transition target)
        {
            var isEqual = false;

            if (null != (object)target)
            {
                isEqual = CompareWithWildCard(source.Field, target.Field)
                          && CompareWithWildCard(source.From, target.From) 
                          && CompareWithWildCard(source.To, target.To);
            }

            return isEqual;
        }

        /// <summary>
        /// Compares the with wild card.
        /// </summary>
        /// <param name="a">The first string to compare.</param>
        /// <param name="b">The second string to compare.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.String"/> is equal to the current <see cref="T:System.String"/>; otherwise, false.
        /// </returns>
        private static bool CompareWithWildCard(IEquatable<string> a, string b)
        {
            return a.Equals(b) || a.Equals(Wildcard) || b.Equals(Wildcard);
        }
    }
}